package com.ruoyi.web.controller.service;


import com.alibaba.excel.EasyExcel;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.system.domain.FormSub;
import com.ruoyi.system.domain.OrderDetail;
import com.ruoyi.system.domain.vo.MetricsQuery;
import com.ruoyi.system.domain.vo.OrderListQuery;
import com.ruoyi.system.mapper.FormSubMapper;
import com.ruoyi.system.mapper.OrderDetailMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.WxNewPayService;
import com.ruoyi.system.tools.WxNewPayConfiguration;
import com.ruoyi.web.controller.domain.EnterpriseInfo;
import com.ruoyi.web.controller.domain.RefundRequest;
import com.ruoyi.web.controller.mapper.EnterpriseInfoMapper;
import com.ruoyi.web.controller.tool.LocalDateConverter;
import com.ruoyi.web.controller.tool.RandomStringGenerator;
import com.ruoyi.web.controller.tool.ShortLinkGenerator;
import com.ruoyi.web.controller.vo.*;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.wechat.pay.java.core.http.Constant.*;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class EnterpriseInfoServiceImpl extends ServiceImpl<EnterpriseInfoMapper, EnterpriseInfo> implements IEnterpriseInfoService {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private FormSubMapper formSubMapper;
    @Value("${wxpay.cert-path:/wxpay/apiclient_cert.pem}")
    private String certPath;
    @Value("${wx.pay.privateKey}")
    private String privateKey;
    @Value("${wx.pay.key}")
    private String apiV3Key;
    @Value("${wx.pay.refundCallback}")
    private String wxpayRefundCallback;
    @Value("${wx.pay.appid}")
    private String APP_ID;
    @Value("${wx.pay.mer_id}")
    private String MCH_ID;
    @Value("${wx.pay.path}")
    private String path;
    @Value("${wx.pay.merchantSerialNumber}")
    private String merchantSerialNumber;

    @Value("${alipay.appId}")
    private String alAppId;
    @Value("${alipay.privateKey}")
    private String alPrivateKey;
    @Value("${alipay.publicKey}")
    private String alPublicKey;

    //引入配置文件的值
    public WxNewPayService getNewWxPayService() {
        WxPayConfig payConfig = new WxPayConfig();
        //支付公众号appid
        payConfig.setAppId(APP_ID);
        //支付商户号mchID
        payConfig.setMchId(MCH_ID);
        //支付密钥 微信商户号后台设置的密钥
        payConfig.setMchKey(apiV3Key);
        //支付证书 apiclient_cert.p12结尾
        payConfig.setKeyPath(path);//
        WxNewPayService wxPayService = new WxNewPayConfiguration().wxService(payConfig);
        return wxPayService;
    }

    @Override
    public EnterpriseInfo createEnterpriseInfo(EnterpriseInfo enterpriseInfo) {
        LocalDate now = LocalDate.now();
        enterpriseInfo.setCreatedAt(now);
        enterpriseInfo.setUpdatedAt(now);
        enterpriseInfo.setSource("新增");
        enterpriseInfo.setShortLink(generateUniqueShortLink());
        save(enterpriseInfo);
        return enterpriseInfo;
    }

    @Override
    public TableDataInfo getAllEnterpriseInfo(EnterpriseInfoQuery query) {
        Page<EnterpriseInfo> page = new Page<>(query.getPageNum(), query.getPageSize());
        LambdaQueryWrapper<EnterpriseInfo> queryWrapper = new LambdaQueryWrapper<EnterpriseInfo>()
                .eq(EnterpriseInfo::getDeleted, Boolean.FALSE)
                .like(StringUtils.isNotEmpty(query.getShortLink()), EnterpriseInfo::getShortLink, query.getShortLink())
                .like(StringUtils.isNotEmpty(query.getCreditCode()), EnterpriseInfo::getCreditCode, query.getCreditCode())
                .like(StringUtils.isNotEmpty(query.getName()), EnterpriseInfo::getName, query.getName())
                .like(StringUtils.isNotEmpty(query.getRegistrationNumber()), EnterpriseInfo::getRegistrationNumber, query.getRegistrationNumber())
                .like(StringUtils.isNotEmpty(query.getStatus()), EnterpriseInfo::getStatus, query.getStatus())
                .like(StringUtils.isNotEmpty(query.getLegalRepresentative()), EnterpriseInfo::getLegalRepresentative, query.getLegalRepresentative())
                .like(StringUtils.isNotEmpty(query.getEstablishmentDate()), EnterpriseInfo::getEstablishmentDate, query.getEstablishmentDate())
                .like(StringUtils.isNotEmpty(query.getLastAnnualReportDate()), EnterpriseInfo::getLastAnnualReportDate, query.getLastAnnualReportDate())
                .like(StringUtils.isNotEmpty(query.getProvince()), EnterpriseInfo::getProvince, query.getProvince())
                .like(StringUtils.isNotEmpty(query.getCity()), EnterpriseInfo::getCity, query.getCity())
                .like(StringUtils.isNotEmpty(query.getPhoneNumber()), EnterpriseInfo::getPhoneNumber, query.getPhoneNumber())
                .like(StringUtils.isNotEmpty(query.getOtherPhoneNumber()), EnterpriseInfo::getOtherPhoneNumber, query.getOtherPhoneNumber())
                .like(StringUtils.isNotEmpty(query.getLastReportPhone()), EnterpriseInfo::getLastReportPhone, query.getLastReportPhone())
                .like(StringUtils.isNotEmpty(query.getAddress()), EnterpriseInfo::getAddress, query.getAddress())
                .like(StringUtils.isNotEmpty(query.getOperatingAbnormally()), EnterpriseInfo::getOperatingAbnormally, query.getOperatingAbnormally())
                .like(StringUtils.isNotEmpty(query.getAnnualReportFilterStatus()), EnterpriseInfo::getAnnualReportFilterStatus, query.getAnnualReportFilterStatus())
                .like(StringUtils.isNotEmpty(query.getOperatorType()), EnterpriseInfo::getOperatorType, query.getOperatorType())
                .like(StringUtils.isNotEmpty(query.getOrderCompleted()), EnterpriseInfo::getOrderCompleted, query.getOrderCompleted())
                .like(StringUtils.isNotEmpty(query.getRemark()), EnterpriseInfo::getRemark, query.getRemark());
        List<EnterpriseInfo> list = list(page, queryWrapper);
        long total = page.getTotal();
        return new TableDataInfo(list, (int) total);
    }

    @Override
    public EnterpriseInfo getEnterpriseInfoById(Long id) {
        return getById(id);
    }

    @Override
    public void updateEnterpriseInfo(EnterpriseInfo enterpriseInfo) {
        if (enterpriseInfo.getId() == null) {
            throw new ServiceException("id不能为空");
        }
        if (enterpriseInfo.getName() == null) {
            throw new ServiceException("企业名称不能为空");
        }
        updateById(enterpriseInfo);
    }

    @Override
    public void deleteEnterpriseInfo(Long id) {
        EnterpriseInfo info = new EnterpriseInfo();
        info.setId(id);
        info.setDeleted(true);
        updateById(info);
    }

    @Override
    public void downloadByIds(List<Long> ids, HttpServletResponse response) {
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("ids参数不能为null");
        }
        List<EnterpriseInfo> infos = listByIds(ids);
        Resource resource = new ClassPathResource("template/企业信息导入模版.xlsx");
        try {
            InputStream inputStream = resource.getInputStream();
            ServletOutputStream outputStream = response.getOutputStream();
            EasyExcel.write(outputStream)
                    .withTemplate(inputStream)
                    .registerConverter(new LocalDateConverter())
                    .sheet()
                    .doFill(infos);
            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment; filename=企业信息.xlsx");
            // 关闭模板流
            inputStream.close();
        } catch (IOException e) {
            log.error("导出失败！失败原因：{}", e.getMessage());
            throw new ServiceException("导出失败！");
        }
    }

    public Map<String, Object> refundOrder(RefundRequest refundRequest) {
        // 1. 查询订单信息
        OrderDetail orderDetail = orderDetailMapper.selectOrderDetailById(refundRequest.getId());
        if (orderDetail == null) {
            throw new ServiceException("订单不存在");
        }
        if (!"0".equals(orderDetail.getRefundStatus())) {
            throw new ServiceException("管理员未发起退款不允许操作！");
        }
        // 2. 校验退款金额
        BigDecimal payAmount = orderDetail.getAmount();
        if (payAmount == null) {
            throw new ServiceException("支付金额为null,不能发起退款申请");
        }
//        if (payAmount.compareTo(orderDetail.getPayAmount()) > 0) {
//            throw new ServiceException("退款金额不能大于支付金额");
//        }
        //
        if (!orderDetail.getRefundStatus().equals("0")) {
            throw new ServiceException("该订单状态不能退款");
        }
        try {
            // 3. 调用微信退款
            Config config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(MCH_ID)
                    //使用 SDK 不需要计算请求签名和验证应答签名
                    // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
                    .privateKey(privateKey)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3Key)
                    .build();
            // 构建退款service
            RefundService service = new RefundService.Builder().config(config).build();
            // request.setXxx(val)设置所需参数，具体参数可见Request定义
            //构建退款请求
            CreateRequest request = new CreateRequest();
            //构建订单金额信息
            AmountReq amountReq = new AmountReq();
            //退款金额
            amountReq.setRefund(orderDetail.getAmount().multiply(BigDecimal.valueOf(100)).longValue());
            //原订单金额
            amountReq.setTotal(orderDetail.getAmount().multiply(BigDecimal.valueOf(100)).longValue());
            //货币类型(默认人民币)
            amountReq.setCurrency("CNY");
            request.setAmount(amountReq);
            //商户退款单号
            request.setOutRefundNo(UUID.randomString(24));
            request.setOutTradeNo(orderDetail.getOrderNumber());
            //退款通知回调地址
            request.setNotifyUrl(wxpayRefundCallback);
            // 调用退款方法，得到应答
            // 调用微信sdk接口
            Refund refund = service.create(request);
            // 4. 更新订单状态
            orderDetail.setStatus("2");
            orderDetail.setRefundTime(new Date());
            orderDetail.setRefundAmount(payAmount);
            orderDetail.setRefundStatus("1");
            orderDetail.setRefundAmount(payAmount);
            orderDetail.setRefundReason(refundRequest.getRefundReason());
            orderDetailMapper.updateOrderDetail(orderDetail);
            Map<String, Object> result = new HashMap<>();
            result.put("refundId", refund.getRefundId());
            result.put("refundNo", refund.getOutRefundNo());
            result.put("status", "SUCCESS");
            return result;
        } catch (Exception e) {
            throw new ServiceException("退款异常：" + e.getMessage());
        }
    }

    @Override
    public String getShortLink(ShortLink link) {
        Long id = link.getId();
        Long userId;
        try {
            userId = null == link.getUserId() ? SecurityUtils.getUserId() : link.getUserId();
        } catch (Exception e) {
            throw new ServiceException("登录用户id获取失败!");
        }
        if (id == null) {
            throw new ServiceException("缺少企业id参数！");
        }
        if (userId == null) {
            throw new ServiceException("缺少用户userId参数！");
        }
        SysUser sysUser = sysUserMapper.selectUserById(userId);
        if (null == sysUser) {
            throw new ServiceException("通过userId未获取到用户信息！");
        }
        EnterpriseInfo enterpriseInfo = getById(id);
        if (enterpriseInfo == null) {
            throw new ServiceException("通过企业id未获取到企业信息！");
        }
        String shortLink = enterpriseInfo.getShortLink();
        if (!StringUtils.isEmpty(shortLink)) {
            return shortLink;
        }
        String var = generateUniqueShortLink();
        enterpriseInfo.setShortLink(var);
        enterpriseInfo.setUserId(userId);
        updateById(enterpriseInfo);
        return var;
    }

    @Override
    public Object updateLongLink(List<EnterpriseVO> vo) {
        for (EnterpriseVO v : vo) {
            EnterpriseInfo info = new EnterpriseInfo(v.getId(), v.getLongLink());
            updateById(info);
        }
        return vo;
    }


    public Set<String> generateUniqueShortLinkBatch() {
        Set<String> links;
        do {
            links = RandomStringGenerator.generateUniqueStrings(900);
        } while (isLinkExists1(links));
        return links;
    }

    // 获取短链信息
    public String generateUniqueShortLink() {
        String link;
        do {
            link = ShortLinkGenerator.generateShortLink();
        } while (isLinkExists(link));
        return link;
    }

    private boolean isLinkExists1(Set<String> link) {
        LambdaQueryWrapper<EnterpriseInfo> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(EnterpriseInfo::getId);
        queryWrapper.in(EnterpriseInfo::getShortLink, link);
        return count(queryWrapper) > 0;
    }


    private boolean isLinkExists(String link) {
        LambdaQueryWrapper<EnterpriseInfo> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(EnterpriseInfo::getShortLink, link);
        return count(queryWrapper) > 0;
    }

    //退款回调
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleRefundNotify(HttpServletRequest request) {
        try {
            //读取请求体的信息
            ServletInputStream inputStream = request.getInputStream();
            StringBuffer stringBuffer = new StringBuffer();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String s;
            //读取回调请求体
            while ((s = bufferedReader.readLine()) != null) {
                stringBuffer.append(s);
            }
            String s1 = stringBuffer.toString();
            String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
            String nonce = request.getHeader(WECHAT_PAY_NONCE);
            String signType = request.getHeader("Wechatpay-Signature-Type");
            String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
            String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
            // 如果已经初始化了 RSAAutoCertificateConfig，可直接使用
            // 没有的话，则构造一个
            NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(MCH_ID)
                    .privateKey(privateKey)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3Key)
                    .build();
            // 初始化 NotificationParser
            NotificationParser parser = new NotificationParser(config);
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(serialNo)
                    .nonce(nonce)
                    .signature(signature)
                    .timestamp(timestamp)
                    // 若未设置signType，默认值为 WECHATPAY2-SHA256-RSA2048
                    .signType(signType)
                    .body(s1)
                    .build();
            RefundNotification parse = parser.parse(requestParam, RefundNotification.class);
            System.out.println("parse = " + parse);
            //parse.getRefundStatus().equals("SUCCESS");说明退款成功
            if (parse.getRefundStatus().toString().equals("SUCCESS")) {
                OrderDetail orderDetail = orderDetailMapper.selectOrderDetailByOutTradeNo(parse.getOutTradeNo());
                orderDetail.setStatus("3");
                orderDetail.setRefundStatus("2");
                orderDetail.setRefundTime(new Date());
                orderDetailMapper.updateOrderDetail(orderDetail);
            }
        } catch (Exception e) {
            throw new RuntimeException("回调出错" + e.getMessage());
        }
    }

    /**
     * 验证签名
     */
    private boolean verifySignature(String signature, String serial, String nonce, String timestamp, String body) {
        try {
            String message = timestamp + "\n" + nonce + "\n" + body + "\n";
            X509Certificate certificate = getCertificate(serial);

            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initVerify(certificate.getPublicKey());
            sign.update(message.getBytes(StandardCharsets.UTF_8));

            return sign.verify(Base64.getDecoder().decode(signature));
        } catch (Exception e) {
            log.error("签名验证异常", e);
            return false;
        }
    }

    /**
     * 解密数据
     */
    private String decryptData(String ciphertext, String associatedData, String nonce) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
        GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));

        cipher.init(Cipher.DECRYPT_MODE, key, spec);

        if (associatedData != null) {
            cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
        }

        byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(decrypt, StandardCharsets.UTF_8);
    }

    /**
     * 获取微信支付平台证书
     */
    private X509Certificate getCertificate(String serial) {
        try {
            Resource resource = new ClassPathResource(certPath);
            InputStream inputStream = resource.getInputStream();
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);

            if (serial.equals(cert.getSerialNumber().toString(16).toUpperCase())) {
                return cert;
            }

            log.error("证书序列号不匹配，期望：{}，实际：{}", serial, cert.getSerialNumber().toString(16).toUpperCase());
            throw new RuntimeException("证书序列号不匹配");
        } catch (Exception e) {
            log.error("加载证书失败", e);
            throw new RuntimeException("加载证书失败", e);
        }
    }

    @Override
    public BusinessMetrics businessMetrics(MetricsQuery query) {

        String beginDateTime = query.getBeginDateTime();
        String endDateTime = query.getEndDateTime();
        try {
            LocalDateTime beginLocalDateTime = LocalDateTime.parse(beginDateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            LocalDateTime endLocalDateTime = LocalDateTime.parse(endDateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        } catch (Exception e) {
            throw new ServiceException("beginDateTime  endDateTime 为必传参数，且格式为：yyyy-MM-dd HH:mm:ss");
        }
        if (null != query.getUserName()) {
            SysUser sysUser = sysUserMapper.selectUserByUserName(query.getUserName());
            if (null != sysUser) {
                LambdaQueryWrapper<EnterpriseInfo> eq = new LambdaQueryWrapper<EnterpriseInfo>()
                        .eq(EnterpriseInfo::getUserId, sysUser.getUserId())
                        .last("LIMIT 1");
                EnterpriseInfo one = getOne(eq);
                if (null != one) {
                    query.setUserKey(one.getShortLink());
                }
            }
        }
        // 订单数
        Integer orderCount = Optional.ofNullable(orderDetailMapper.selectOrderCount(query)).orElse(0);
        // 已完成的订单数
        Integer completedOrderCount = Optional.ofNullable(orderDetailMapper.selectCompletedOrderCount(query)).orElse(0);
        // 短链key数
        Integer shortLinkKeyCount = Optional.ofNullable(orderDetailMapper.selectShortLinkKeyCount(query)).orElse(0);
        // h5登录数量
        Integer loginH5Count = Optional.ofNullable(orderDetailMapper.selectloginH5Count(query)).orElse(0);
        // 短链登录数量
        Integer loginShortLinkCount = Optional.ofNullable(orderDetailMapper.selectLoginShortLinkCount(query)).orElse(0);
        // 交易金额
        Double transactionAmount = Optional.ofNullable(orderDetailMapper.selectTransactionAmount(query)).orElse(0D);
        // 退款金额
        Double refundAmount = Optional.ofNullable(orderDetailMapper.selectRefundAmount(query)).orElse(0D);

        List<Map<String, Object>> orderTypeList = orderDetailMapper.selectOrderTypeCount(query);
        List<Map<String, Object>> orderPayTypeList = orderDetailMapper.selectOrderPayTypeCount(query);


        return BusinessMetrics.builder()
                .orderCount(orderCount)
                .completedOrderCount(completedOrderCount)
                .shortLinkKeyCount(shortLinkKeyCount)
                .loginH5Count(loginH5Count)
                .loginShortLinkCount(loginShortLinkCount)
                .transactionAmount(transactionAmount)
                .refundAmount(refundAmount)
                .orderTypeList(orderTypeList)
                .orderPayTypeList(orderPayTypeList)
                .build();
    }

    @Override
    public EnterpriseInfo selectEnterpriseInfoByShortLink(String shortLink) {
        LambdaQueryWrapper<EnterpriseInfo> queryWrapper = new LambdaQueryWrapper<EnterpriseInfo>()
                .eq(EnterpriseInfo::getShortLink, shortLink)
                .last("LIMIT 1");

        return getOne(queryWrapper);
    }

    @Override
    public void batchDelByIds(List<Long> ids) {
        if (null == ids || ids.isEmpty()) {
            return;
        }
        update(null, new LambdaUpdateWrapper<EnterpriseInfo>()
                .in(EnterpriseInfo::getId, ids)
                .set(EnterpriseInfo::getDeleted, true)
        );
    }

    public TableDataInfo listIsShortLinkNotEmpty(EnterpriseInfoQuery query) {
        Long userId = null;
        try {
            userId = SecurityUtils.getUserId();
        } catch (Exception e) {
            log.error("登录用户获取失败");
        }
        Page<EnterpriseInfo> page = new Page<>(query.getPageNum(), query.getPageSize());
        LambdaQueryWrapper<EnterpriseInfo> queryWrapper = new LambdaQueryWrapper<EnterpriseInfo>()
                .isNotNull(EnterpriseInfo::getShortLink)
                .eq(null != userId, EnterpriseInfo::getUserId, userId)
                .like(StringUtils.isNotEmpty(query.getCreditCode()), EnterpriseInfo::getCreditCode, query.getCreditCode())
                .like(StringUtils.isNotEmpty(query.getName()), EnterpriseInfo::getName, query.getName())
                .like(StringUtils.isNotEmpty(query.getRegistrationNumber()), EnterpriseInfo::getRegistrationNumber, query.getRegistrationNumber());
        List<EnterpriseInfo> list = list(page, queryWrapper);
        long total = page.getTotal();
        return new TableDataInfo(list, (int) total);
    }


    public void startRefund(Integer id, String refundReason) {
        if (null == id) {
            throw new ServiceException("id参数不能为null!");
        }
        OrderDetail orderDetail = orderDetailMapper.selectOrderDetailById(id);
        if (null == orderDetail) {
            throw new ServiceException("订单信息不存在");
        }
        String refundStatus = orderDetail.getRefundStatus();
        if ("0".equals(refundStatus)) {
            throw new ServiceException("已发起退款操作,请勿重复操作！");
        }
        orderDetailMapper.updateRefundStatusById(id, "0", null == refundReason ? "" : refundReason);
    }

    public AjaxResult alipayRefundOrder(RefundRequest refundRequest) {
        // 1. 查询订单信息
        OrderDetail orderDetail = orderDetailMapper.selectOrderDetailById(refundRequest.getId());
        if (orderDetail == null) {
            throw new ServiceException("订单不存在");
        }
        // 2. 校验退款金额
//        if (refundRequest.getRefundAmount().compareTo(orderDetail.getPayAmount()) > 0) {
//            throw new ServiceException("退款金额不能大于支付金额");
//        }
        if (!orderDetail.getRefundStatus().equals("0")) {
            throw new ServiceException("该订单状态不能退款");
        }
        try {
            // 3. 调用支付宝退款API
            AlipayClient alipayClient = new DefaultAlipayClient(
                    "https://openapi.alipay.com/gateway.do",
                    alAppId,
                    alPrivateKey,
                    "json",
                    "utf-8",
                    alPublicKey,
                    "RSA2"
            );
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            request.setBizContent("{" +
                    "\"out_trade_no\":\"" + orderDetail.getOrderNumber() + "\"," +
                    "\"refund_amount\":" + orderDetail.getAmount() + "," +
                    "\"refund_reason\":\"" + refundRequest.getRefundReason() + "\"" +
                    "}");
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            // 4. 更新订单状态
            if (response.isSuccess()) {
                orderDetail.setStatus("3");
                orderDetail.setRefundStatus("2");
                orderDetail.setRefundTime(new Date());
                orderDetail.setRefundAmount(orderDetail.getAmount());
                orderDetail.setRefundReason(refundRequest.getRefundReason());
                orderDetailMapper.updateOrderDetail(orderDetail);
                return AjaxResult.success("支付宝退款成功");
            } else {
                throw new ServiceException("退款失败：" + response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            throw new ServiceException("退款异常：" + e.getMessage());
        }
    }

    /**
     * 查询订单信息
     */
    public TableDataInfo selectOrderDetailList(OrderListQuery query) {
        // 查询订单
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(query);
        // 通过UserKey 查询企业
        Set<String> userKeyList = orderDetails.stream().map(OrderDetail::getUserKey).collect(Collectors.toSet());
        LambdaQueryWrapper<EnterpriseInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(EnterpriseInfo::getShortLink, userKeyList);
        List<EnterpriseInfo> list = userKeyList.isEmpty() ? new ArrayList<>() : list(queryWrapper);
        // k 短链 ， v 企业信息
        Map<String, EnterpriseInfo> enterpriseInfoMap = list.stream().collect(Collectors.toMap(EnterpriseInfo::getShortLink, Function.identity(), (key1, key2) -> key2));

        // 查询form表
        Set<Integer> formId = orderDetails.stream().map(OrderDetail::getFormSubId).collect(Collectors.toSet());
        List<FormSub> formSubList = formId.isEmpty() ? new ArrayList<>() : formSubMapper.selectByIds(formId);
        // k formId, v form表单信息
        Map<Integer, FormSub> formSubMap = formSubList.stream().collect(Collectors.toMap(FormSub::getId, obj -> obj));

        ArrayList<OrderListVo> orderListVos = new ArrayList<>();
        for (OrderDetail detail : orderDetails) {
            orderListVos.add(new OrderListVo(detail, formSubMap.get(detail.getFormSubId()), enterpriseInfoMap.get(detail.getUserKey())));
        }

        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(orderListVos);
        rspData.setTotal(new PageInfo(orderDetails).getTotal());
        return rspData;
    }

    public void orderUpdateNew(OrderListVo vo) {
        if (null == vo) {
            return;
        }
        OrderDetail orderDetail = vo.getOrderDetail();
        if (null != orderDetail && null != orderDetail.getId()) {
            orderDetailMapper.updateOrderDetailNew(orderDetail);
        }
        FormSub formSub = vo.getFormSub();
        if (null != formSub && null != formSub.getId()) {
            formSubMapper.update(formSub);
        }
    }

    public String orderListLast() {
        List<OrderDetail> orderDetails = orderDetailMapper.orderListLast10();
        if (null == orderDetails) {
            return null;
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ArrayList<OrderDetailJson> list = new ArrayList<>();
        orderDetails.forEach(obj -> {
            OrderDetailJson build = OrderDetailJson.builder()
                    .businessName(extractFirstTwoCharacters(obj.getBusinessName()) + "...")
                    .userName(desensitizeName(obj.getUserName()))
                    .tel(desensitizePhoneNumber(obj.getTel()))
                    .payTime(dateFormat.format(obj.getPayTime()))
                    .payType("已支付")
                    .build();
            list.add(build);
        });
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsString(list);
        } catch (JsonProcessingException e) {
            return null;
        }
    }

    public String desensitizePhoneNumber(String phoneNumber) {
        if (phoneNumber == null || phoneNumber.length() < 7) {
            return phoneNumber;
        }
        // 保留前三位和后四位，中间用星号替换
        String prefix = phoneNumber.substring(0, 3);
        String suffix = phoneNumber.substring(phoneNumber.length() - 4);
        StringBuilder masked = new StringBuilder();
        for (int i = 0; i < phoneNumber.length() - 7; i++) {
            masked.append("*");
        }
        return prefix + masked + suffix;
    }

    public static String extractFirstTwoCharacters(String input) {
        if (input == null || input.isEmpty()) {
            return "";
        }
        return input.substring(0, Math.min(input.length(), 2));
    }

    public static String desensitizeName(String name) {
        if (name == null || name.isEmpty()) {
            return "---";
        }
        int length = name.length();
        if (length == 2) {
            // 两个字的姓名，脱敏最后一个字
            return name.charAt(0) + "*";
        } else if (length > 2) {
            // 大于两个字的姓名，脱敏中间部分
            StringBuilder desensitized = new StringBuilder();
            desensitized.append(name.charAt(0)); // 保留第一个字符
            for (int i = 1; i < length - 1; i++) {
                desensitized.append("*"); // 中间字符用星号替换
            }
            desensitized.append(name.charAt(length - 1)); // 保留最后一个字符
            return desensitized.toString();
        } else {
            return name;
        }
    }

    public String getLongLinkByShortLink(String shortLink) {
        if (null == shortLink || shortLink.isEmpty()) {
            return "";
        }
        LambdaQueryWrapper<EnterpriseInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EnterpriseInfo::getShortLink, shortLink).last("LIMIT 1");
        EnterpriseInfo one = getOne(queryWrapper);
        return null == one ? null : one.getLongLink();
    }
}
